package project.platform;

import java.util.*;

import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;

import project.Animal;


/**
 * 2BA7 Project Platform Test MIDlet to interact with servlet 
 * using an HttpConnection and to demonstate sending and receiving
 * Animal objects by MMS.
 *
 * Note: if you run this inside POSE using a multi-homed PC (with more
 * than one network connections), POSE doesn't know how to resolve
 * host names not connected to the first network card. To solve this,
 * add a line like this in your c:/WINNT/system32/drivers/etc/hosts
 * file.
 * 
 * @author Paul Magrath - 05379725
 *
 */
public class TestMidlet extends MIDlet implements CommandListener, Runnable {
    /** User interface command to exit the current application. */
    private final Command exitCommand = new Command("Exit", Command.EXIT, 2);

    /** User interface command to issue a request to get animals from servlet. */
    private final Command servletReceiveCommand = new Command("Receive from Servlet", Command.SCREEN, 1);

    /** User interface command to issue a request to send an animal to servlet. */
    private final Command servletSendCommand = new Command("Send to Servlet", Command.SCREEN, 1);
    
    /** User interface command to issue a request to send an animal by MMS. */
    private final Command mmsSendCommand = new Command("Send by MMS", Command.SCREEN, 1);
    
    /** User interface command to issue a request to receive an animal by MMS. */
	private Command mmsReceiveCommand = new Command("Receive by MMS", Command.SCREEN, 1);

    /** User interface command to choose a test. */
    private final Command chooseCommand = new Command("Choose", Command.SCREEN, 2);

    /** User interface command to confirm current operation. */
    private final Command okCommand = new Command("OK", Command.OK, 1);

    /** User interface command to abort current operation. */
    private final Command cancelCommand = new Command("Cancel", Command.CANCEL, 1);
    
    /** User interface command to store the animal received by MMS. */
    private final Command Store = new Command("Store", Command.SCREEN, 1);

    /** The current display object. */
    private Display display;
    
    /** The animal to send */
    private Animal animalTest;

    /** Array of animals that could be sent. */
    private Vector testCases;

    /** User interface list for selection. */
    private List list;

    /** Current command to process. */
    private Command currentCommand;

    /** The current command processing thread. */
    private Thread commandThread;
    
    /** The application-ID on which we send MMS messages */
    private String appID;

    /** Area where the user enters the phone number to send the message to */
    private TextField destinationField;

    /** Error message displayed when an invalid phone number is entered */
    private Alert errorMessageAlert;

    /** Alert that is displayed when a message is being sent */
    private Alert sendingMessageAlert;

    /** The screen used to prompt for the phone number to send the MMS to */
    private Form mmsSendScreen = null;
    
    /** The screen used to display the incoming MMS */
    private Form mmsReceiveScreen = null;

    /** Text Box to display messages on screen */
    private TextBox textBox;
    
    /** Boolean for if this is or is not the first run */
    private boolean firstTime;

    /** Initialize the MIDlet with a handle to the current display */
    public TestMidlet() {
    	/* set up animal storage */
        this.testCases = new Vector();
        this.testCases.addElement(new Animal("Monkey1"));
        this.testCases.addElement(new Animal("Monkey2"));
        this.animalTest = (Animal) this.testCases.elementAt(0);

        /* set up menus */
        this.display = Display.getDisplay(this);
        this.firstTime = true;
        
        /* set up mms stuff */
        appID = getAppProperty("MMS-ApplicationID");

        mmsSendScreen = createSendForm();
        mmsReceiveScreen = createReceiveForm();

        errorMessageAlert = new Alert("MMS", null, null, AlertType.ERROR);
        errorMessageAlert.setTimeout(5000);

        sendingMessageAlert = new Alert("MMS", null, null, AlertType.INFO);
        sendingMessageAlert.setTimeout(1000);
        sendingMessageAlert.setCommandListener(this);
    }

    /** 
     * Create MMS send form. 
     * Takes in destination phone number.
     * @return Form for the sending of MMS messages.
     */
	private Form createSendForm() {
		Form mmsSendForm = new Form("New MMS");
        destinationField = new TextField("Destination Address: ", "mms://", 256, TextField.ANY);
        mmsSendForm.append(destinationField);
        mmsSendForm.addCommand(okCommand);
        mmsSendForm.addCommand(cancelCommand);
        mmsSendForm.setCommandListener(this);
        return mmsSendForm;
	}
	
	/** 
	 * Create MMS receive screen .
	 * Shows a "Receiving..." message during the act.
	 * @return Form for the receipt of MMS messages.
	 */
	private Form createReceiveForm() {
		Form mmsReceiveScreen = new Form("MMS Receive");
        mmsReceiveScreen.addCommand(cancelCommand);
        mmsReceiveScreen.addCommand(Store);
        mmsReceiveScreen.setCommandListener(this);
        mmsReceiveScreen.append("Receiving...");
        return mmsReceiveScreen;
	}

    /**
     * Debug output routine.
     * @param s string to be printed.
     */
    private static final void DEBUG(final String s) {
        if (true)
			System.out.println(s);
    }

    /**
     * Start creates the thread to do the timing.
     * It should return immediately to keep the dispatcher
     * from hanging.
     */
    public void startApp() {
        if (this.firstTime) {
            this.mainScreen();
            this.firstTime = false;
        } else
			this.display.setCurrent(this.textBox);
    }

    /**
     * Display the main screen.
     */
    void mainScreen() {
        final String s =
            "Press the right menu button and choose between sending and" +
            " receiving of animals from server, or MMS"+
            " or Choose to use another animal.";
        this.textBox = new TextBox("2BA7 Group 5 - Comms Platform", s, s.length(), 0);
        this.setCommands(this.textBox, false);
        this.display.setCurrent(this.textBox);
    }

    /**
     * Display screen used to pick an Animal to use for sending.
     */
    void chooseScreen() {
        this.list = new List("Choose Animal", Choice.EXCLUSIVE);

        for (int i = 0; i < this.testCases.size(); i++)
			this.list.append(((Animal)this.testCases.elementAt(i)).toString(), null);

        this.setCommands(this.list, true);
        this.display.setCurrent(this.list);
    }

    /**
	 * Test the communications with the servlet.
	 * @param requestType type of request ("Send" or "Receive")
	 * @param a Animal to send (ignored if request is "Receive")
	 */
	private void testServlet(final String requestType, final Animal a) {
		boolean success = false;
		if (requestType == "Send")
			// first parameter should be taken in by dialog
			// second parameter should by set by user at first run
			success = Platform.sendToServer(a, "testuser", "testuser");
		else{
			// parameter should be set by user at first run
			final Object[] newTestCases = Platform.receiveFromServer("testuser");
			success = newTestCases!=null;
			if (success)
				addNewToStored(newTestCases);
		}
		String result = "";
		if (success)
			result =  "Operation completed successfully.";
		else
			result = "Operation failed.";
		this.textBox = new TextBox("Result", result, result.length(),0);
	    this.setCommands(this.textBox, false);
	    this.display.setCurrent(this.textBox);
	}

	/**
	 * Add new test cases to the vector where they are stored.
	 * Synchronized for thread-safety.
	 * @param newTestCases
	 */
	private synchronized void addNewToStored(final Object[] newTestCases) {
		TestMidlet.DEBUG("Adding "+newTestCases.length+" new test cases.");
		for (int i = 0; i<newTestCases.length; i++){
			TestMidlet.DEBUG("Adding: "+newTestCases[i].toString());
			this.testCases.addElement(newTestCases[i]);
		}
	}

	/**
     * Set the funtion to perform based on commands selected.
     * @param d Displayable object
     * @param islist flag to indicate list processing
     */
    void setCommands(final Displayable d, final boolean islist) {
        if (islist)
			d.addCommand(this.okCommand);
		else {
            d.addCommand(this.exitCommand);
            d.addCommand(this.chooseCommand);
            d.addCommand(this.servletReceiveCommand);
            d.addCommand(this.servletSendCommand);
            d.addCommand(this.mmsSendCommand);
            d.addCommand(this.mmsReceiveCommand);
        }

        d.setCommandListener(this);
    }

    /**
     * Pause signals the thread to stop by clearing the thread field.
     * If stopped before done with the iterations it will
     * be restarted from scratch later.
     */
    public void pauseApp() {
    }

    /**
     * Destroy must cleanup everything.  The thread is signaled
     * to stop and no result is produced.
     * @param unconditional Flag to indicate that forced shutdown
     * is requested
     */
    public void destroyApp(final boolean unconditional) {
    }

    /**
     * Respond to commands, including exit
     * @param c command to perform
     * @param s Screen displayable object
     */
    public void commandAction(final Command c, final Displayable s) {
        synchronized (this) {
            try {
            	if ((s == mmsSendScreen) && (c == okCommand)) 
            		Platform.sendByMMS(
            				this.destinationField.getString(), 
            				animalTest, 
            				sendingMessageAlert, 
            				errorMessageAlert, 
            				appID, 
            				display);
            	if ((s == mmsReceiveScreen) && (c == Store)){
            		this.addNewToStored(Platform.getMMS());
            		this.chooseScreen();
            	}
            		
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        	
            if (this.commandThread != null)
				// process only one command at a time
                return;

            this.currentCommand = c;
            this.commandThread = new Thread(this);
            this.commandThread.start();
        }
    }

    /**
     * Perform the current command set by the method commandAction.
     */
    public void run() {
    	
        if (this.currentCommand == this.exitCommand) {
            this.destroyApp(false);
            this.notifyDestroyed();
        } else if (this.currentCommand == this.servletReceiveCommand)
			this.testServlet("Receive", null);
		else if (this.currentCommand == this.servletSendCommand)
			this.testServlet("Send", this.animalTest);
		else if (this.currentCommand == this.chooseCommand)
			this.chooseScreen();
		else if (this.currentCommand == this.mmsReceiveCommand){
			Platform.receiveMMS(appID,display,this.mmsReceiveScreen);
			this.display.setCurrent(this.mmsReceiveScreen);
		}
		else if (this.currentCommand == this.mmsSendCommand)
			this.display.setCurrent(mmsSendScreen);
		else if (this.currentCommand == this.okCommand) {
            final int i = this.list.getSelectedIndex();

            if (i >= 0)
				this.animalTest = (Animal) this.testCases.elementAt(i);

            this.mainScreen();
        } else if (this.currentCommand == this.cancelCommand)
			this.mainScreen();
        else if (this.currentCommand == Alert.DISMISS_COMMAND ) {
        	// Return from MMS sending.
        	mainScreen();
        }

        synchronized (this) {
            // signal that another command can be processed
            this.commandThread = null;
        }
    }
}
